﻿using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using YNTK.Common.Const;
using YNTK.Common.Enum;
using YNTK.Common.Filter;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.LinqBuilder;
using YNTK.Mapster;
using YNTK.System.Entitys.Dto.Resources;
using YNTK.System.Entitys.Resources;
using YNTK.System.Interfaces.Common;
using YNTK.System.Interfaces.Resources;

namespace YNTK.System.Service.Resources
{
    /// <summary>
    /// 友情链接
    /// 版 本：V1.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022-10-02 
    /// </summary>
    [ApiDescriptionSettings(Tag = "友情链接", Name = "Link", Order = 796)]
    [Route("api/[controller]")]
    public class LinkService: ILinkService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<LinkEntity> _linkRepository;//友情链接仓储
        private readonly IMongoDBRepository<LinkEntity> _linkMongoDbRepository;//友情链接mongodb仓储
        private readonly IFileService _fileService;//文件服务

        private readonly HttpContext _httpContext;
        private readonly string _links = "base_link";//mongodb中友情链接数据集名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="linkRepository">友情链接仓储</param>
        /// <param name="linkMongoDbRepository">友情链接mongodb仓储</param>
        /// <param name="fileService">文件服务</param>
        public LinkService(ISqlSugarRepository<LinkEntity> linkRepository,
            IMongoDBRepository<LinkEntity> linkMongoDbRepository,
            IFileService fileService)
        {
            _linkRepository = linkRepository;
            _linkMongoDbRepository = linkMongoDbRepository;
            _fileService = fileService;
            _httpContext = App.HttpContext;
        }

        /// <summary>
        /// 获取友情链接列表数据
        /// </summary>
        /// <param name="enabled">启用/禁用,2.全部 1.启用 0.禁用</param>
        /// <returns></returns>
        [HttpGet("gets/{enabled}")]
        public async Task<TkResult<List<LinkListDto>>> Gets(int? enabled)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;

            #region 拼接查询条件
            Expression<Func<LinkEntity, bool>> where = m => m.OrganizeId == organizeId && m.DeleteMark == null;
            if (enabled == 1) where = where.And(m => m.EnabledMark == 1);
            if (enabled == 0) where = where.And(m => m.EnabledMark != 1);
            #endregion

            //先从mongodb中获取友情链接数据
            var data = await _linkMongoDbRepository.GetListAsync(_links, where);
            if (!data.Any())
            {
                //再从sqlserver中获取友情链接数据
                data = await _linkRepository.Entities.Where(where).ToListAsync();
            }            
            var list = data.Adapt<List<LinkListDto>>();
            if (list.Any())
            {
                list = list.OrderBy(r => r.sortCode).ToList();
                list.ForEach(link =>
                {
                    if (!string.IsNullOrWhiteSpace(link.logUrl))
                        link.logUrlBase64 = _fileService.GetImageBase64(link.logUrl);
                });
            }
            return TkResult<List<LinkListDto>>.Success(list);
        }

        /// <summary>
        /// 添加友情链接
        /// </summary>
        /// <param name="input">添加友情链接请求模型</param>
        /// <returns></returns>
        [HttpPost("add")]
        public async Task Add([FromBody] AddLinkRequestModel input)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;

            if ((await GetLinkInfoAsync(o => o.Name == input.name && 
            o.OrganizeId == organizeId && o.DeleteMark == null))!=null)
                throw YNTKException.Oh("名称已存在");
            if ((await GetLinkInfoAsync(o => o.Link == input.link && 
            o.OrganizeId == organizeId && o.DeleteMark == null))!=null)
                throw YNTKException.Oh("链接已存在");

            var entity = input.Adapt<LinkEntity>();
            entity.OrganizeId = organizeId;//所属组织id
            var isOk = await _linkRepository.Context.Insertable(entity)
                .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
            _ = isOk ?? throw YNTKException.Oh("添加友情链接失败");

            //保存友情链接到mongodb
            entity = isOk;
            var result = await _linkMongoDbRepository.AddAsync(entity, _links);
            if (!result) throw YNTKException.Oh("mongodb添加友情链接失败");
        }

        /// <summary>
        /// 修改友情链接
        /// </summary>
        /// <param name="input">修改友情链接请求模型</param>
        /// <returns></returns>
        [HttpPut("update")]
        public async Task Update([FromBody] UpdateLinkRequestModel input)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;

            var entity = await GetLinkInfoAsync(o => o.Id == input.id && o.DeleteMark == null);
            _ = entity ?? throw YNTKException.Oh("友情链接不存在");
            if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);
            if ((await GetLinkInfoAsync(o => o.Name == input.name && 
            o.OrganizeId == organizeId && o.Id != input.id && o.DeleteMark == null))!=null)
                throw YNTKException.Oh("名称已存在");
            if ((await GetLinkInfoAsync(o => o.Link == input.link && 
            o.OrganizeId == organizeId && o.Id != input.id && o.DeleteMark == null))!=null)
                throw YNTKException.Oh("链接已存在");

            //var entity = input.Adapt<LinkEntity>();
            entity = input.Mapper(entity);
            var isOK = await _linkRepository.Context.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true)
                .CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
            if (!(isOK > 0)) throw YNTKException.Oh("更新友情链接失败");

            //保存字典值到mongodb
            var update = await _linkMongoDbRepository.UpdateAsync(entity, _links, m => m.Id == entity.Id);
            if (!(update.ModifiedCount > 0)) throw YNTKException.Oh("mongodb更新友情链接失败");
        }

        /// <summary>
        /// 删除友情链接
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        [HttpDelete("delete/{id}")]
        public async Task Delete([Required] string id)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;

            var entity = await GetLinkInfoAsync(o => o.Id == id && o.DeleteMark == null);
            _ = entity ?? throw YNTKException.Oh("友情链接不存在");
            if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

            //先从sqlserver中删除
            var isOk = await _linkRepository.Context.Deleteable(entity).ExecuteCommandAsync();
            if (!(isOk > 0)) throw YNTKException.Oh("删除友情链接失败");

            //再从mongodb中删除
            var delete = await _linkMongoDbRepository.DeleteAsync(_links, m => m.Id == id);
            if (!(delete > 0)) throw YNTKException.Oh("mongodb删除友情链接失败");
        }

        /// <summary>
        /// 更新友情链接状态(启用/禁用)
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        [HttpPut("state/{id}")]
        public async Task UpdateState([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                
                var entity = await GetLinkInfoAsync(u => u.Id == id && u.DeleteMark == null);              
                _ = entity ?? throw YNTKException.Oh("友情链接不存在");
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

                //更新sqlserver中友情链接状态
                var isOk = await _linkRepository.Context.Updateable<LinkEntity>().SetColumns(it => new LinkEntity()
                {
                    EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                    LastModifyUserId = userId,
                    LastModifyTime = SqlFunc.GetDate()
                }).Where(it => it.Id == id).ExecuteCommandAsync();
                if (!(isOk > 0))
                    throw YNTKException.Oh("更新友情链接状态失败");

                //更新mongodb中友情链接状态
                entity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var update = await _linkMongoDbRepository.UpdateAsync(entity, _links, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh("mongodb更新友情链接状态失败");
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"更新友情链接状态(启用/禁用)发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 同步友情链接数据(开发人员同步专用)
        /// </summary>
        /// <param name="type">0.sqlserver同步mongodb 1.mongodb同步sqlserver</param>
        /// <param name="organizeId">要同步的组织id</param>
        /// <returns></returns>
        [HttpPut("synchronous/{type}")]
        public async Task Synchronous([Required] int type, string organizeId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType != "1" || (type != 0 && type != 1)) throw YNTKException.Oh(ErrorCode.D1016);
                _linkRepository.Ado.BeginTran();
                List<LinkEntity> data = null;
                Expression<Func<LinkEntity, bool>> where = r => r.DeleteMark == null;
                if (!string.IsNullOrWhiteSpace(organizeId)) where = where.And(r => r.OrganizeId == organizeId);
                if (type == 0)
                {
                    data = await _linkRepository.Entities.Where(where).ToListAsync();
                    if (data.Any())
                    {
                        //删除mongodb原数据
                        await _linkMongoDbRepository.DeleteAsync(_links, where);
                        //保存到mongodb
                        var succeed = await _linkMongoDbRepository.AddListAsync(data, _links);
                        if (!succeed) throw YNTKException.Oh("友情链接数据sqlserver同步mongodb失败");
                    }
                }
                if (type == 1)
                {
                    data = await _linkMongoDbRepository.GetListAsync(_links, where);
                    if (data.Any())
                    {
                        //删除sqlserver原数据
                        await _linkRepository.DeleteAsync(where);
                        //保存到sqlserver                 
                        var isOk = await _linkRepository.Context.Insertable(data).ExecuteCommandAsync();
                        if (!(isOk > 0)) throw YNTKException.Oh("友情链接数据mongodb同步sqlserver失败");
                    }
                }
                _linkRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _linkRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"同步友情链接数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据条件获取友情链接信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<LinkEntity> GetLinkInfoAsync(Expression<Func<LinkEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _linkMongoDbRepository.GetAsync(_links, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _linkRepository.FirstOrDefaultAsync(where);
            return entity;
        }

    }
}
